//
// Copyright (c) 2009 Tridium, Inc.
// Licensed under the Academic Free License version 3.0
//
// History:
//   24 Feb 09  Dan Giorgis  Creation
//

#include "sedona.h"

#include <time.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <linux/fs.h>
#include <errno.h>
#include <string.h>
#include "math.h"


static float 	out_c=0;
static float 	raw_c=0;
static int 		channel_c=1;
static int 		inputType_c=3;		// Voltage, 0 to 5v
static float 	scaleLow_c=0;
static float	scaleHigh_c=100;
static float	offset_c=0;
static float	lowCutOff_c=0;
static bool 	cutOffEnable_c=0;
static bool 	squareRoot_c=0;
static int		decimalPoint_c=2;
static int		tempTable_c=1;
static float	digitalOnLevel_c=55;
static float	digitalOffLevel_c=-45;

static float 	outTemp_c;
static float	rawTemp_c;

// for analogInputStatusData
static int 		reliablity_c=0;
static float 	max_c=0;
static float	min_c=0;

// for analogInputAlarm
static bool 	alarm_c=0;
static bool	high_c=0;
static bool	low_c=0;
static bool	highEnable_c=0;
static float	highLimit_c=100;
static bool	lowEnable_c = 0;
static float 	lowLimit_c=0;
static float	deadband_c=1;
static int		delay_c=5;
static bool	manualReset_c=0;




////////////////////////////////////////////////////////////////
// Native Methods
////////////////////////////////////////////////////////////////

//  Temparature (0 - 100 oC) <=> Voltage (0 - 3.3 v)

Cell vonplusBasic_aip_get(SedonaVM* vm, Cell* params)
{
  //int32_t a = params[0].fval;
  //int32_t b = params[1].fval;

        int channel = params[0].ival;     // later used for the selection of ADC channel

  	int32_t value;
  
  	int fd = open("/dev/adc", 0);
	if (fd < 0) {
		perror("open ADC device:");
		return zeroCell;
	}
	//for(;;) {
		char buffer[30];
		int len = read(fd, buffer, sizeof buffer -1);
		if (len > 0) {
			buffer[len] = '\0';
//			int value = -1;
			sscanf(buffer, "%d", &value);
			//printf("ADC Value: %d\n", value);
		} else {
			perror("read ADC device:");
			return oneCell;
		}
	//	usleep(500* 1000);
	//}
	
	
	  close(fd);
	  
	  Cell result;
	  float ainValue;

          // to see if it need the square root operation for AIN.
	  if (squareRoot_c==0)
	  	ainValue = (float)((float)value/(float)1023);
	  else
	  	ainValue = (float)((((float)value/(float)1023)*100)/100);   //sqrt

   //    printf("input type: %d\n", inputType_c);
	//   printf("ain value: %f\n", ainValue);

        // based on the different input type for AIN.
	switch (inputType_c)
	{
	   case 0: 
	          outTemp_c= (float) (ainValue*(scaleHigh_c-scaleLow_c) + scaleLow_c + offset_c); 
	        break;
	    case 1: 
	          outTemp_c= (float) (ainValue*(scaleHigh_c-scaleLow_c) + scaleLow_c + offset_c); 
	        break;
	    case 2:
	          outTemp_c= (float) (ainValue*(scaleHigh_c-scaleLow_c) + scaleLow_c + offset_c); 
	        break;
	    case 3: 
	          outTemp_c= (float) (ainValue*(scaleHigh_c-scaleLow_c) + scaleLow_c + offset_c); 
	        break;
	    case 4:
	          outTemp_c= (float) (ainValue*(scaleHigh_c-scaleLow_c) + scaleLow_c + offset_c); 
	        break;
	    case 5: 
	          outTemp_c= (float) (ainValue*(scaleHigh_c-scaleLow_c) + scaleLow_c + offset_c); 
	        break;
	    case 6:
	          outTemp_c= (float) (ainValue*(scaleHigh_c-scaleLow_c) + scaleLow_c + offset_c); 
	        break;
	    case 7: 
	          outTemp_c= (float) (ainValue*(scaleHigh_c-scaleLow_c) + scaleLow_c + offset_c); 
	        break;
	    case 8:
	          outTemp_c= (float) (ainValue*(scaleHigh_c-scaleLow_c) + scaleLow_c + offset_c); 
	        break;
	    default:
	          outTemp_c= (float) (ainValue*(scaleHigh_c-scaleLow_c) + scaleLow_c + offset_c); 
	        break;
	}

       if (outTemp_c<=lowCutOff_c)
	  	outTemp_c = scaleLow_c + offset_c;


	// setup for the alarm
	 if ((highEnable_c==1)&&(outTemp_c>=highLimit_c))
	 {	high_c = 1;   low_c=0; alarm_c = 1; }

	 if ((lowEnable_c==1)&&(outTemp_c<=lowLimit_c))
	 {	low_c = 1;   high_c=0; alarm_c = 1; }

	 if ((highEnable_c==1)&&(outTemp_c<=highLimit_c-deadband_c)&&(outTemp_c>lowLimit_c))
	 {	high_c = 0;  alarm_c = 0; }

	 if ((lowEnable_c==1)&&(outTemp_c>=lowLimit_c+deadband_c)&&(outTemp_c<highLimit_c))
	 {	low_c = 0;  alarm_c = 0; }

	

     /*   // the limitation by scale low and cut off low value
	  if ((outTemp_c <= scaleLow_c)||(outTemp_c<=lowCutOff_c))
	  	outTemp_c = scaleLow_c;

       // the limitation by scale high
	  if (outTemp_c>=scaleHigh_c)
	  	outTemp_c = scaleHigh_c;
      */
      
	  result.fval = outTemp_c;
	  //result.fval = (float)value;
	   
	  return result;
}







Cell vonplusBasic_aip_getRaw(SedonaVM* vm, Cell* params)
{

  //  printf("inputType_c= %d\n", inputType_c);

	 int32_t value;
  
  	int fd = open("/dev/adc", 0);
	if (fd < 0) {
		perror("open ADC device:");
		return zeroCell;
	}

	char buffer[30];
	int len = read(fd, buffer, sizeof buffer -1);
	if (len > 0) {
		buffer[len] = '\0';
//		int value = -1;
		sscanf(buffer, "%d", &value);
		//printf("ADC Value: %d\n", value);
	} else {
		perror("read ADC device:");
		return oneCell;
	}

	
	  close(fd);
	  
          Cell result;
	  float ainValue;

          // to see if it need the square root operation for AIN.	  
	  ainValue = (float)((float)value/1023);
	

        // based on the different input type for AIN.
	switch (inputType_c)
	{
	   
	
	    case 0: 
	          rawTemp_c= (float) (ainValue*(20-4) + 4); 
	        break;
	    case 1: 
	          rawTemp_c= (float) (ainValue*(20-0) + 0); 
	        break;
	    case 2:
	          rawTemp_c= (float) (ainValue*(10-0) + 0); 
	        break;
	    case 3: 
	          rawTemp_c= (float) (ainValue*(5-0) + 0); 
	        break;
	    case 4:
	          rawTemp_c= (float) (ainValue*(30-0) + 0); 
	        break;
	    case 5: 
	          rawTemp_c= (float) (ainValue*(10-0) + 0); 
	        break;
	    case 6:
	          rawTemp_c= (float) (ainValue*(1.5-0) + 0); 
	        break;
	    case 7: 
	          rawTemp_c= (float) (ainValue*(10-0) + 0); 
	        break;
	    case 8:
	          rawTemp_c= (float) (ainValue*(10-0) + 0); 
	        break;
	    default:
	          rawTemp_c= (float) (ainValue*(5-0) + 0); 
	        break;
	}

       
	  result.fval = rawTemp_c;
	   
	  return result;

	 
}




Cell vonplusBasic_aip_getStatus(SedonaVM* vm, Cell* params)
{
	channel_c = params[0].ival;    
	params[1].ival = reliablity_c;

        if (max_c<=outTemp_c) 
			max_c=outTemp_c;

	if(min_c>=outTemp_c)
		min_c=outTemp_c;
	
	params[2].ival = max_c;
	params[3].ival = min_c;
	
	return zeroCell;
}

Cell vonplusBasic_aip_setScaleLow(SedonaVM* vm, Cell* params)
{
       channel_c = params[0].ival;    
	float scaleLow = params[1].fval;    

	if (inputType_c<=3) // only for the current and voltages (0, 1, 2, 3)
	{
		scaleLow_c= scaleLow;
	}
  
  	 return zeroCell;

}

Cell vonplusBasic_aip_setScaleHigh(SedonaVM* vm, Cell* params)
{

        channel_c= params[0].ival;    
	float scaleHigh = params[1].fval;    

	if (inputType_c<=3) // only for the current and voltages (0, 1, 2, 3)
	{
		scaleHigh_c= scaleHigh;
	}
	printf("scaleHigh: %f\n", scaleHigh_c);
  
  	 return zeroCell;
}


Cell vonplusBasic_aip_setLowCutOff(SedonaVM* vm, Cell* params)
{
	channel_c = params[0].ival;    
	float lowCutOff = params[1].fval;    

	if (inputType_c<=3) // only for the current and voltages (0, 1, 2, 3)
	{
		lowCutOff_c= lowCutOff;
	}
  
  	 return zeroCell;
}

Cell vonplusBasic_aip_setOffset(SedonaVM* vm, Cell* params)
{
	channel_c= params[0].ival;    

	offset_c = params[1].fval;    

	printf("offset: %f\n", offset_c);

  	 return zeroCell;
}

Cell vonplusBasic_aip_setDigitalOnLevel(SedonaVM* vm, Cell* params)
{

	channel_c= params[0].ival;    

	digitalOnLevel_c = params[1].fval;    

  	 return zeroCell;
}

Cell vonplusBasic_aip_setDigitalOffLevel(SedonaVM* vm, Cell* params)
{

	channel_c = params[0].ival;    

	digitalOffLevel_c = params[1].fval;    

  	 return zeroCell;
}

Cell vonplusBasic_aip_setInputType(SedonaVM* vm, Cell* params)
{
	channel_c = params[0].ival;    

	printf("inputType_c= %d (before) \n", inputType_c);

	inputType_c = params[1].ival;    

	printf("inputType_c= %d (after) \n", inputType_c);

  	 return zeroCell;
}

Cell vonplusBasic_aip_setTempTable(SedonaVM* vm, Cell* params)
{

	channel_c= params[0].ival;    

	tempTable_c = params[1].fval;    

  	 return zeroCell;
}

Cell vonplusBasic_aip_setDecimalPoint(SedonaVM* vm, Cell* params)
{

	channel_c = params[0].ival;    

	decimalPoint_c = params[1].fval;    

  	 return zeroCell;
}

Cell vonplusBasic_aip_setCutOffEnable(SedonaVM* vm, Cell* params)
{
        channel_c = params[0].ival;    
	float cutOffEnable = params[1].fval;    

	if (inputType_c<=3) // only for the current and voltages (0, 1, 2, 3)
	{
		cutOffEnable_c= cutOffEnable;
	}
  
  	 return zeroCell;
}

Cell vonplusBasic_aip_setLinearization(SedonaVM* vm, Cell* params)
{

	channel_c = params[0].ival;    

	squareRoot_c = params[1].fval;    

  	 return zeroCell;
}

Cell vonplusBasic_aip_resetMaximumValue(SedonaVM* vm, Cell* params)
{
	channel_c = params[0].ival;    

	max_c = outTemp_c;    


	return zeroCell;
}

Cell vonplusBasic_aip_resetMinimumValue(SedonaVM* vm, Cell* params)
{

        channel_c = params[0].ival;    

	min_c = outTemp_c;    


	return zeroCell;
}

Cell vonplusBasic_aip_getAlarm(SedonaVM* vm, Cell* params)
{
 	Cell result;
	channel_c = params[0].ival;    

	if ((alarm_c==1)&&(high_c==0)&&(low_c==1))
		result.ival = 1;
	else if ((alarm_c==1)&&(high_c==1)&&(low_c==0))
		result.ival = 2;    
	else
		result.ival = 3;   

	return result;
}

Cell vonplusBasic_aip_setAlarmHighEnable(SedonaVM* vm, Cell* params)
{
	channel_c = params[0].ival;    
	highEnable_c = params[1].ival; 

	return zeroCell;
}

Cell vonplusBasic_aip_setAlarmLowEnable(SedonaVM* vm, Cell* params)
{
	channel_c = params[0].ival;    
	lowEnable_c = params[1].ival; 
	
	return zeroCell;
}

Cell vonplusBasic_aip_setAlarmHighLimit(SedonaVM* vm, Cell* params)
{

	channel_c = params[0].ival;    
	highLimit_c = params[1].fval; 

	return zeroCell;
}

Cell vonplusBasic_aip_setAlarmLowLimit(SedonaVM* vm, Cell* params)
{
	channel_c = params[0].ival;    
	lowLimit_c = params[1].fval; 

	return zeroCell;
}

Cell vonplusBasic_aip_setAlarmDeadband(SedonaVM* vm, Cell* params)
{

	channel_c = params[0].ival;    
	deadband_c = params[1].fval; 

	return zeroCell;
}

Cell vonplusBasic_aip_setAlarmDelayTime(SedonaVM* vm, Cell* params)
{
	channel_c = params[0].ival;    
	delay_c = params[1].ival; 

	return zeroCell;
}

Cell vonplusBasic_aip_setAlarmResetType(SedonaVM* vm, Cell* params)
{

	channel_c = params[0].ival;    
	manualReset_c = params[1].ival; 

	return zeroCell;
}

Cell vonplusBasic_aip_resetAlarm(SedonaVM* vm, Cell* params)
{

	channel_c = params[0].ival;    
	
	alarm_c=0;
	high_c=0;
	low_c=0;
	highEnable_c=0;
	highLimit_c=100;
	lowEnable_c=0;
	lowLimit_c=0;
	deadband_c=1;
	delay_c=5;
	manualReset_c=0;

	return zeroCell;
}












